package org.thinginitself.mixpath.jdom;

import org.jaxen.JaxenConstants;
import org.jaxen.jdom.DocumentNavigator;
import org.jaxen.util.SingleObjectIterator;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.Namespace;

import java.util.Iterator;
import java.util.List;

/**
 * @author Andrew Harrison
 * @version 1.0.0 16/05/2011
 */
public class JDomMiXPathNavigator extends DocumentNavigator {

    private static JDomMiXPathNavigator INSTANCE = new JDomMiXPathNavigator();

    public static JDomMiXPathNavigator getNavigator() {
        return INSTANCE;
    }

    public Iterator getChildAxisIterator(
            Object contextNode, String localName, String namespacePrefix, String namespaceURI) {

        if (contextNode instanceof Element) {
            Element node = (Element) contextNode;
            if (namespaceURI == null) {
                List l = node.getChildren(localName);
                if (l.size() == 0) {
                    Element child = new Element(localName);
                    node.addContent(child);
                    return new SingleObjectIterator(child);
                } else {
                    return l.iterator();
                }
            } else {
                List l = node.getChildren(localName, Namespace.getNamespace(namespaceURI));
                if (l.size() == 0) {
                    String pref = getPrefix(node, namespaceURI);
                    Namespace ns = Namespace.getNamespace(pref, namespaceURI);
                    Element child;
                    child = new Element(localName, ns);
                    node.addContent(child);
                    return new SingleObjectIterator(child);
                } else {
                    return l.iterator();
                }
            }
        } else if (contextNode instanceof Document) {
            Document node = (Document) contextNode;

            Element el = null;
            try {
                el = node.getRootElement();
            } catch (java.lang.IllegalStateException e) {

            }
            if (el == null) {
                if (namespaceURI != null) {

                    Namespace ns = Namespace.getNamespace(namespaceURI);
                    Element child;
                    if (ns.getPrefix() != null && ns.getPrefix().length() > 0) {
                        child = new Element(localName, ns);
                    } else {
                        child = new Element(localName, namespaceURI);
                    }
                    node.addContent(child);
                    return new SingleObjectIterator(child);
                } else {
                    Element child = new Element(localName);
                    node.addContent(child);
                    return new SingleObjectIterator(child);
                }
            } else {

                if (el.getName().equals(localName) == false) {
                    return JaxenConstants.EMPTY_ITERATOR;
                }
                if (namespaceURI != null) {
                    // JDOM's equals method does not consider the prefix when comparing namespace objects
                    if (!Namespace.getNamespace(namespacePrefix, namespaceURI).equals(el.getNamespace())) {
                        return JaxenConstants.EMPTY_ITERATOR;
                    }
                } else if (el.getNamespace() != Namespace.NO_NAMESPACE) {
                    return JaxenConstants.EMPTY_ITERATOR;
                }

                return new SingleObjectIterator(el);
            }
        } else {
            return JaxenConstants.EMPTY_ITERATOR;
        }
    }

    private String getPrefix(Element node, String uri) {
        while(node != null) {
            if (node.getNamespaceURI().equals(uri)) {
                if (node.getNamespacePrefix() != null) {
                    return node.getNamespacePrefix();
                }
            }
            node = node.getParentElement();
        }
        return null;
    }
}
